import random
from datetime import datetime, timezone
import requests
import json
import re
import uuid
import hashlib
import random
from urllib3.exceptions import InsecureRequestWarning

# 禁用不安全请求的警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)


class Data:
    LastNames = ["Adams", "Allen", "Amos", "Ayers", "Adler", "Avery", "Akers", "Ashby", "Alton", "Angel", "Abbot",
                 "Ames", "Arden", "Aiken", "Ault", "Asher", "Axel", "Albin", "Acker", "Aches", "Alves", "Ashby",
                 "Alden", "Ayala", "Adair", "Alvey", "Brown", "Burke", "Banks", "Baird", "Boyd", "Blake", "Baker",
                 "Bates", "Black", "Beard", "Bond", "Byers", "Beach", "Buck", "Bower", "Baird", "Bales", "Bryan",
                 "Bowie", "Brady", "Bunn", "Baum", "Cain", "Carr", "Chen", "Choi", "Cole", "Cook", "Cox", "Cruz",
                 "Caino", "Cline", "Cross", "Cavan", "Cabel", "Caius", "Creed", "Cappy", "Cates", "Caffa", "Carrs",
                 "Cobb", "Cairn", "Crump", "Caddy", "Cabel", "Combs", "Coutu", "Cawth", "Coone", "Cloyd", "Creek",
                 "Davis", "Diaz", "Dean", "Dunn", "Dale", "Dyer", "Day", "Doyle", "Drury", "Dumas", "Dove", "Dowdy",
                 "Duong", "Duffy", "Damon", "Devan", "Delac", "Delon", "Danks", "Drago", "Dolly", "Dumas", "Durel",
                 "Duvet", "Dallm", "Domen", "Dabne", "Darcy", "Degas", "Dasho", "Evans", "Ellis", "Estes", "Ewing",
                 "East", "Eason", "Eaton", "Eden", "Elson", "Edmon", "Elder", "Eller", "Eanes", "Eades", "Eades",
                 "Estey", "Estab", "Eager", "Earle", "Earby", "Evers", "Early", "Edens", "Ewart", "Edlin", "Elsey",
                 "Ebron", "Eldre", "Ewald", "Eanes", "Ford", "Fong", "Frost", "Fife", "Floyd", "Finch", "Frank",
                 "Farah", "Frees", "Fawke", "Field", "Fitch", "Fultz", "Fonte", "Flann", "Freid", "Fairb", "Fleck",
                 "Freya", "Felty", "Flana", "Feron", "Farra", "Fashe", "Feist", "Felle", "Franq", "Fitch", "Fawls",
                 "Fulch", "Gray", "Gao", "Gould", "Green", "Goff", "Grant", "Glenn", "Gale", "Grier", "Gower", "Giles",
                 "Goode", "Gaski", "Guthr", "Grier", "Giebe", "Goudy", "Gallo", "Gavil", "Gantz", "Galen", "Gagne",
                 "Geary", "Goude", "Gambl", "Groce", "Golly", "Greve", "Gulik", "Hill", "Hu", "Hunt", "Huang", "Hall",
                 "Holt", "Hayes", "Hodge", "Hoang", "Hood", "Hines", "Hogan", "Heard", "Haney", "Hager", "Hartz",
                 "Hanks", "Hasty", "Hagan", "Higby", "Hadda", "Hamed", "Haddo", "Havil", "Hesby", "Hulce", "Haydo",
                 "Hawes", "Hilly", "Irwin", "Inman", "Ivy", "Isaak", "Ivers", "Irvin", "Ibbot", "Irani", "Ianni",
                 "Isler", "Ishak", "Imhof", "Inaba", "Iacop", "Icard", "Idris", "Igoe", "Ingli", "Ienco", "Iiams",
                 "Isele", "Isola", "Ianna", "Imrie", "Itani", "Ishma", "Ianni", "Isner", "Ildem", "Iqbal", "Jones",
                 "Jin", "Jang", "James", "Johns", "Jung", "Judd", "Jolly", "Joyal", "Jaber", "Joyce", "Jakes", "Jeter",
                 "Jolly", "Jines", "Judge", "Jevon", "Jessu", "Junki", "Jolli", "Jarry", "Janda", "Jeste", "Jodar",
                 "Jaska", "Jowit", "Jobin", "Jouts", "Jiron", "King", "Kim", "Khan", "Kaur", "Kirk", "Kelly", "Knox",
                 "Kimb", "Koons", "Kowal", "Kiley", "Kline", "Keele", "Kitch", "Kiser", "Kagle", "Kinca", "Knoll",
                 "Kadel", "Kozak", "Kuper", "Korns", "Kaler", "Kagan", "Kapel", "Karis", "Kinne", "Krier", "Lee",
                 "Lopez", "Lewis", "Lane", "Lowe", "Lyon", "Lakin", "Lyman", "Loney", "Latta", "Louie", "Leman",
                 "Langl", "Lisle", "Landa", "Loney", "Lueck", "Ludwi", "Lalka", "Landy", "Lambe", "Luebb", "Latif",
                 "Lafon", "Layto", "Moore", "Mason", "Myers", "Mayes", "Mayer", "Moses", "Moyer", "Mabry", "Monti",
                 "Morle", "Mulli", "Mahon", "Mcgee", "Macha", "Macle", "Moseb", "Molin", "Mazza", "Mcgil", "Maran",
                 "Mccur", "Mayol", "Nolan", "Nash", "Nunez", "Najar", "Nason", "Naima", "Nason", "Naylo", "Noone",
                 "Neal", "Nasir", "Nyber", "Nishm", "Nyqui", "Nault", "Neier", "Nason", "Nolte", "Navid", "Nogue",
                 "Neff", "Navar", "Nemer", "Naeem", "Ortiz", "Odom", "Olsen", "Owen", "Orr", "Osman", "Oakle", "Obert",
                 "Oconn", "Oyler", "Odell", "Oberg", "Ozawa", "Oliv", "Olmos", "Ohara", "Osped", "Oliph", "Oberm",
                 "Odono", "Olaya", "Omary", "Osler", "Oconn", "Onley", "Olins", "Ondre", "Perez", "Price", "Perry",
                 "Pena", "Pasha", "Pryor", "Parr", "Palme", "Papp", "Paine", "Pilli", "Payet", "Pogue", "Penni",
                 "Panko", "Pavlo", "Peopl", "Pucel", "Pined", "Pitte", "Persa", "Pacel", "Pasqu", "Pogue", "Quinn",
                 "Quick", "Quigl", "Quang", "Quill", "Quach", "Quave", "Quigg", "Quaid", "Qadir", "Qamar", "Quito",
                 "Qiana", "Quale", "Quate", "Quire", "Quarn", "Quock", "Qadri", "Quane", "Qadry", "Qadir", "Qasim",
                 "Qawwi", "Qamar", "Quail", "Quern", "Quilo", "Quero", "Quent", "Reed", "Ramos", "Rios", "Ricks",
                 "Raine", "Roper", "Rouse", "Ruddy", "Rocha", "Reddy", "Raabe", "Renne", "Raman", "Ranso", "Renda",
                 "Roush", "Rinal", "Ruzic", "Ruben", "Randl", "Ruzek", "Russe", "Rudes", "Smith", "Scott", "Soren",
                 "Sager", "Solor", "Schmi", "Stahl", "Swans", "Spenc", "Scrog", "South", "Sherw", "Skala", "Sable",
                 "Sigle", "Serra", "Sotol", "Sprui", "Swind", "Terry", "Tyler", "Tracy", "Tello", "Tejed", "Teagu",
                 "Trott", "Trinh", "Tread", "Thibe", "Teixe", "Tzeng", "Teagu", "Tufte", "Traub", "Tovey", "Thoms",
                 "Tuthi", "Tress", "Tidwe", "Uribe", "Upton", "Ullom", "Unger", "Uyeda", "Unruh", "Utter", "Usher",
                 "Udell", "Umana", "Updeg", "Umeki", "Usman", "Upsha", "Urbah", "Uthof", "Umlau", "Urias", "Umezu",
                 "Umber", "Ugaki", "Ubell", "Uzzel", "Utsey", "Ushij", "Usher", "Vega", "Velez", "Vicki", "Vose",
                 "Vessi", "Vestb", "Valli", "Veale", "Venab", "Vogel", "Vlaho", "Valla", "Veenb", "Vause", "Verdu",
                 "Vallo", "Vilch", "Vinal", "Viera", "Wood", "White", "Webb", "Wade", "Wong", "Wu", "Welch", "Wolf",
                 "Wang", "Winsl", "Wurth", "Wylde", "Witte", "Wenzl", "Wilds", "Wibbe", "Wasem", "Xiong", "Xinyu",
                 "Xaio", "Xabat", "Xeno", "Xenos", "Xylas", "Yang", "Young", "Yoder", "Yoon", "York", "Yu", "Yates",
                 "Yen", "Yeo", "Ying", "Yeoh", "Yau", "Yanes", "Yohe", "Yancy", "Yee", "Zajac", "Zayas", "Zabel",
                 "Zaitz"]
    FirstNames = ["Abe", "Ada", "Aja", "Ali", "Amos", "Ana", "Ann", "Ara", "Asa", "Ash", "Ava", "Ace", "Adah", "Adan",
                  "Aden", "Adin", "Bao", "Bay", "Beau", "Beck", "Bell", "Ben", "Beth", "Bess", "Bibi", "Bill", "Bing",
                  "Bird", "Bo", "Cai", "Cal", "Cam", "Cap", "Cara", "Carl", "Cass", "Chad", "Chaz", "Cher", "Chip",
                  "Chet", "Cian", "Ciel", "Ciji", "Clay", "Clem", "Cleo", "Cobb", "Coco", "Colt", "Con", "Cook", "Cora",
                  "Cove", "Coy", "Cruz", "Curt", "Cade", "Cain", "Cale", "Cali", "Cami", "Cari", "Cary", "Cash", "Cate",
                  "Cece", "Chia", "Cia", "Clea", "Clio", "Cloe", "Cody", "Cole", "Cori", "Cory", "Cyra", "Dale", "Dane",
                  "Dan", "Dara", "Dave", "Dawn", "Dean", "Deb", "Debi", "Dee", "Del", "Dell", "Demi", "Dena", "Deni",
                  "Desi", "Dev", "Dido", "Dina", "Dino", "Dion", "Dirk", "Don", "Dona", "Donn", "Dora", "Dori", "Dory",
                  "Doug", "Dove", "Drue", "Dyan", "Ed", "Ean", "Earl", "Ebba", "Edie", "Edna", "Eddy", "Eden", "Egan",
                  "Egil", "Eija", "Eira", "Ekin", "Elan", "Elda", "Elin", "Elka", "Ella", "Elle", "Elma", "Elmo",
                  "Elon", "Elsa", "Elsi", "Elva", "Ely", "Emi", "Emma", "Emmy", "Ena", "Enid", "Enna", "Enno", "Enya",
                  "Eoin", "Eola", "Eric", "Erin", "Erle", "Eryn", "Esa", "Esau", "Esme", "Etta", "Etty", "Euan", "Eula",
                  "Euna", "Evan", "Eve", "Ewan", "Fae", "Fawn", "Fay", "Faye", "Fern", "Finn", "Fion", "Flip", "Flo",
                  "Floy", "Flyn", "Ford", "Fran", "Fred", "Gabe", "Gael", "Gail", "Gale", "Gall", "Gari", "Gary", "Gay",
                  "Gene", "Gena", "Gia", "Gigi", "Gil", "Gita", "Glen", "Grae", "Gris", "Guy", "Hale", "Hal", "Han",
                  "Hank", "Hans", "Harv", "Hawk", "Haze", "Herb", "Hero", "Hill", "Hope", "Hoyt", "Huey", "Hugh",
                  "Hugo", "Hula", "Hunt", "Iain", "Ian", "Ida", "Ike", "Ilan", "Ilse", "Ina", "Indi", "Ines", "Inga",
                  "Ione", "Iris", "Irma", "Isa", "Isla", "Ita", "Ivan", "Jace", "Jack", "Jade", "Jael", "Jake", "Jale",
                  "Jana", "Jane", "Jax", "Jay", "Jean", "Jed", "Jeff", "Jena", "Jenn", "Jess", "Jet", "Jett", "Jia",
                  "Jill", "Jim", "Jo", "Joan", "Job", "Jock", "Joe", "Joel", "Joey", "John", "Joli", "Jon", "Joss",
                  "Jude", "Judy", "Jule", "Juna", "June", "Juno", "Juri", "Kade", "Kai", "Kaja", "Kala", "Kale", "Kali",
                  "Kari", "Kate", "Kato", "Katy", "Kay", "Kea", "Keb", "Kee", "Keir", "Keli", "Ken", "Kent", "Kera",
                  "Keta", "Kev", "Keva", "Kian", "Kia", "Kiel", "Kiki", "Kim", "Kip", "Kira", "Kirk", "Kit", "Kitt",
                  "Kiva", "Kobe", "Koda", "Kofi", "Koi", "Koko", "Kole", "Kora", "Kori", "Kory", "Krys", "Kyan", "Kyle",
                  "Kyra", "Lacy", "Ladd", "Lake", "Lana", "Lane", "Lara", "Lark", "Lars", "Lave", "Law", "Lea", "Leaf",
                  "Leah", "Leal", "Lee", "Leif", "Lela", "Leli", "Lely", "Lena", "Leni", "Leo", "Leon", "Les", "Leta",
                  "Lev", "Levi", "Lew", "Lex", "Lida", "Lila", "Lili", "Lily", "Lima", "Lina", "Link", "Lino", "Lira",
                  "Lisa", "Lise", "Liv", "Liza", "Loa", "Lodi", "Loki", "Lola", "Loma", "Loni", "Lora", "Lou", "Love",
                  "Luce", "Lucy", "Luke", "Luna", "Lyle", "Lyn", "Lynn", "Lynx", "Lyon", "Lyra", "Lys", "Lysa", "Macy",
                  "Mada", "Mae", "Maia", "Maja", "Mal", "Mali", "Man", "Mara", "Marc", "Mare", "Mari", "Mark", "Mars",
                  "Mary", "Matt", "Max", "Maya", "Mead", "Meda", "Meg", "Mel", "Meli", "Mell", "Mena", "Merl", "Mick",
                  "Mike", "Mila", "Mimi", "Min", "Mira", "Mo", "Moe", "Mona", "Moon", "Moss", "Moya", "Muir", "Mya",
                  "Myka", "Myra", "Nada", "Nala", "Nan", "Nana", "Nani", "Nara", "Nate", "Neal", "Neel", "Neil", "Nell",
                  "Nena", "Neo", "Nero", "Neta", "Neva", "Nia", "Nick", "Nico", "Nida", "Niki", "Nila", "Nils", "Nima",
                  "Nina", "Nino", "Nita", "Niva", "Nix", "Noah", "Noam", "Nola", "Noli", "Nona", "Nora", "Noya", "Nuri",
                  "Nyah", "Nyx", "Oak", "Obe", "Obi", "Octa", "Odin", "Ola", "Olaf", "Oleg", "Oli", "Olly", "Oma",
                  "Omar", "Ona", "Onyx", "Oona", "Ora", "Oran", "Orca", "Oren", "Orin", "Orly", "Os", "Osca", "Osha",
                  "Otis", "Otto", "Ova", "Owen", "Oz", "Pace", "Pack", "Pal", "Pall", "Pam", "Pat", "Paul", "Paz",
                  "Peg", "Penn", "Pepa", "Per", "Pete", "Phil", "Pike", "Poe", "Posy", "Quin", "Rae", "Raj", "Raji",
                  "Ram", "Rami", "Rani", "Raul", "Ray", "Raye", "Rea", "Reba", "Reed", "Reid", "Remi", "Rene", "Reno",
                  "Renu", "Rex", "Rey", "Rhea", "Rhys", "Rich", "Rick", "Rico", "Rina", "Rio", "Risa", "Rita", "Roan",
                  "Rob", "Roc", "Roch", "Rod", "Roe", "Rolf", "Rome", "Ron", "Rosa", "Rose", "Rosi", "Ross", "Roxy",
                  "Roy", "Roz", "Ruby", "Rudi", "Rudy", "Rue", "Rune", "Russ", "Ruth", "Sade", "Sage", "Said", "Sal",
                  "Sam", "Sami", "Samy", "Sana", "Sara", "Sean", "Seth", "Shay", "Shea", "Shiv", "Sia", "Sian", "Sid",
                  "Siri", "Sita", "Skye", "Snow", "Sol", "Star", "Sue", "Suki", "Suzy", "Tad", "Tai", "Tait", "Tal",
                  "Tam", "Tan", "Tana", "Tara", "Tate", "Ted", "Teo", "Tera", "Tess", "Thad", "Theo", "Thor", "Tim",
                  "Tina", "Tino", "Toby", "Todd", "Tom", "Toni", "Tony", "Tori", "Tove", "Trey", "Troy", "Tula", "Ty",
                  "Tyra", "Una", "Val", "Van", "Veda", "Vega", "Vena", "Vera", "Vern", "Vic", "Vita", "Viv", "Vlad",
                  "Wade", "Walt", "Wes", "West", "Will", "Win", "Wolf", "Wren", "Wyn", "Xav", "Yael", "Yale", "Yan",
                  "Yana", "Yani", "Yara", "Yen", "Yi", "Yoko", "Yuri", "Zac", "Zach", "Zack"]
    Hosts = ["@gmail.com", "@hotmail.com", "@outlook.com", "@yahoo.com"]


class SampleClass:
    def __init__(self, skuId, path):
        self.skuId = skuId
        self.path = path


class AddressClass:
    def __init__(self):
        self.firstName = ""
        self.lastName = ""
        self.phone = ""
        self.address1 = ""
        self.address2 = ""
        self.postalCode = ""
        self.city = ""
        self.state = ""
        self.addressId = ""


class SephoraClass:
    firstName = None
    lastName = None
    birthDay = None
    birthMonth = None
    birthYear = None
    email = None
    password = None
    deviceId = ""
    consumerKey = ""
    consumerSecret = ""
    apiAccessToken = ""
    accessToken = ""
    refreshToken = ""
    ssiToken = ""
    profileId = ""
    sample1 = ""
    sample2 = ""
    sample3 = ""
    couponCode = ""

    httpClient = requests.Session()
    httpClient.headers.update({
        "Accept": "*/*",
        "AAV": "23.6.1",
        "IAV": "23.20",
        "x-sephora-channel": "iPhone15,3",
        # "x-requested-source": "iosApp",
        "x-requested-source": "Sephora 23.20, iOS 17.0.3, iPhone15,3",
        "Content-Type": "application/json; charset=utf-8"})

    def Sha256String(self, data):
        sha256Hash = hashlib.sha256()
        sha256Hash.update(data.encode('utf-8'))
        return sha256Hash.hexdigest()

    def SephoraPost(self, url, data, withSensor=False, withEid=False):
        self.httpClient.headers.update({
            "Content-Type": "application/json; charset=utf-8"})
        ts = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S UTC")
        hdts0 = f"{self.deviceId}{int(datetime.now().timestamp())}000"
        hdts = self.Sha256String(hdts0)
        # print(hdts)
        self.httpClient.headers.pop("SAAT", None)
        # print(f"------------------{self.apiAccessToken}")
        self.httpClient.headers["SAAT"] = self.apiAccessToken
        self.httpClient.headers.pop("TS", None)
        self.httpClient.headers["TS"] = ts
        self.httpClient.headers.pop("HDTS", None)
        self.httpClient.headers["HDTS"] = hdts
        if withSensor:
            self.httpClient.headers.pop("X-acf-sensor-data", None)
            # self.httpClient.headers[
            #     "X-acf-sensor-data"] = "2,a,tEGjKtpM89TVQ1JVkR2gqRPpDmRWVfIbuFc+lOFD7mTq1nmQASkJwsMdtCmH1aQPT0dkBOKQgDV0iHkSIyML5fn15K5yWQnEltvo+fa17pouWeV0w6eKhQJfE0K78OQzw/VnStRs/l5zf91/cJ1zEWD5k3ESrbb5JLYrN5P7vEE="
            self.httpClient.headers[
                "X-acf-sensor-data"] = "4,i,Gvez8hcNeTYlg770tRx6kqIILJyjJ8YG0dOks6b312LZxVdJdNlrTx7w/Fpu6qSsN1MJmVgBaMFLECJawCCWjggo4XOzS+ua/AO7+YB3rwZ+a1fPqY4k9LsPmjglwpii6Hq3d+bHa7xBjZPjm/rZ3iM/vPW4ZzWalKsHq19B4r4=,DYNASihG00aUtj6akD+0MqIPDJfZD9JcfAuPrACogBWdrdV37d59tlmH+Z4tkHN5+f+USaB84J3xOjTVqjmgt4JyhH3z8HGdKRmxqfecXXT9JC7BMDXYrYs8jBN+DN+LSsMjsHrWJU6p/WXuzxU/+MbjZZOo09D3oGptcMpSgHQ=$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$12,9,40$$$AAQAAAAA%2f%2f%2f%2f%2f6Bypk0FFv9P2PWEy6sQW6WtQhuP8iO1sARZlC6ddmnvNARtB8ySKX0iuame6FvTOswXO7tmheAY0nPCS96mbCw15893iL6ADDC7ygi4Ddsh3CMoOVEDWcJE1a2B8hz9uGf6HftnooCcRO8gKGSHAbUe184EC8h9+BVuWcEehieLuOlRH%2fSpWxKLwabbJ4ftNYppucbXLWuvBcPdVVAF2vrh7E%2frh6M%2fMC6ZMU1bjRmjnpL6BbqPJA%3d%3d"
        if withEid:
            self.httpClient.headers.pop("Mobile_Efm_Id", None)
            self.httpClient.headers["Mobile_Efm_Id"] = "2d0341d0542c7db137c00e1388522ea48ddf6ff89"
        try:
            response = self.httpClient.post(url, data, headers=self.httpClient.headers, verify=False)
            return response.text
        except Exception as ex:
            return str(ex)

    def SephoraGet(self, url):
        ts = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S UTC")
        hdts0 = f"{self.deviceId}{int(datetime.now().timestamp())}000"
        hdts = self.Sha256String(hdts0)
        self.httpClient.headers.pop("SAAT", None)
        self.httpClient.headers["SAAT"] = self.apiAccessToken
        self.httpClient.headers.pop("TS", None)
        self.httpClient.headers["TS"] = ts
        self.httpClient.headers.pop("HDTS", None)
        self.httpClient.headers["HDTS"] = hdts
        response = self.httpClient.get(url, headers=self.httpClient.headers)
        return response.text

    def SephoraDelete(self, url):
        ts = datetime.now(timezone.utc).strftime("%a, %d %b %Y %H:%M:%S UTC")
        hdts0 = f"{self.deviceId}{int(datetime.now().timestamp())}000"
        hdts = self.Sha256String(hdts0)
        self.httpClient.headers.pop("SAAT", None)
        self.httpClient.headers["SAAT"] = self.apiAccessToken
        self.httpClient.headers.pop("TS", None)
        self.httpClient.headers["TS"] = ts
        self.httpClient.headers.pop("HDTS", None)
        self.httpClient.headers["HDTS"] = hdts
        response = self.httpClient.delete(url, headers=self.httpClient.headers)
        return response.text

    # 注册设备，获取设备ID
    def registerDevice(self):
        msg = ""
        url = "https://api.sephora.com/v1/oauth/registerDevice"
        data = {"skey": "2c04a666f11b3f22a6dc2658938e28cfa7862d189fb31b477ffbf5eebe2bde2c"}
        # headers = {"Content-Type": "application/json; charset=utf-8"}
        str1 = self.SephoraPost(url, json.dumps(data))
        print(str1)
        if not str:
            return False, msg
        elif "Access Denied" in str1:
            msg = "Access Denied : You don't have permission to access \"" + url + "\" on this server"
            return False, msg
        elif "errorMessages" in str1:
            error_messages = json.loads(str1)
            msg = error_messages.get("errorMessages", "")
            return False, msg
        elif "由于目标计算机积极拒绝，无法连接" in str1:
            msg = "请打开Fiddler"
            return False, msg
        else:
            jobj = json.loads(str1)
            self.deviceId = jobj.get("deviceId", "")
            print(f"deviceId:{self.deviceId}")
            return True, self.deviceId

    # 认证设备ID，获取消费者密钥
    def AuthenticateDevice(self):
        msg = ""
        url = "https://api.sephora.com/v1/oauth/authenticateDevice"
        # skey 是一个定值
        data = {"deviceId": self.deviceId}

        # 调用 SephoraPost 方法发送 POST 请求
        str1 = self.SephoraPost(url, json.dumps(data), False, False)

        if not str:
            return False, msg

        # 使用正则表达式提取错误消息
        error_message_match = re.search(r'"errorMessage":"(.*?)"', str1)
        if error_message_match:
            msg = error_message_match.group(1)
            return False, msg
        else:
            jobj = json.loads(str1)
            self.consumerKey = jobj.get("consumerKey", "")
            self.consumerSecret = jobj.get("consumerSecret", "")
            print(f"consumerKey:{self.consumerKey},consumerSecret:{self.consumerSecret}")
            return True

    # 通过消费者密钥，获取apiAccessToken
    def AccessToken(self):
        msg = ""
        url = "https://api.sephora.com/v1/oauth/accessToken"
        data = {"consumerKey": self.consumerKey, "consumerSecret": self.consumerSecret}

        # 调用 SephoraPost 方法发送 POST 请求
        str1 = self.SephoraPost(url, json.dumps(data), True, False)

        if not str:
            return False, msg

        # 使用正则表达式提取错误消息
        error_messages_match = re.search(r'"errorMessages":\["(.*?)"\\]', str1)
        if error_messages_match:
            msg = error_messages_match.group(1)
            return False, msg

        try:
            jobj = json.loads(str1)
            self.apiAccessToken = jobj.get("apiAccessToken", "")
            print(f"apiAccessToken:{self.apiAccessToken}")
            return True, None
        except Exception:
            msg = str1
            return False, msg

    def generate_infos(self, firstName, lastName, birthDay, birthMonth, birthYear, email, password):
        if not lastName:
            self.lastName = random.choice(Data.LastNames)
        if not firstName:
            self.firstName = random.choice(Data.FirstNames)
        if not birthDay:
            self.birthDay = str(random.randint(1, 28))
        if not birthMonth:
            self.birthMonth = str(random.randint(1, 12))
        if not birthYear:
            self.birthYear = str(random.randint(1970, 2003))
        if not email:
            self.email = f"{self.firstName.lower()}{self.lastName.lower()}{self.birthMonth}{self.birthDay}{random.choice(Data.Hosts)}"
        if not password:
            self.password = ''.join(
                random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz') for _ in range(3)) + ''.join(
                random.choice('0123456789') for _ in range(3))
        # data = {
        #     "isJoinBi": True,
        #     "isKeepSignedIn": True,
        #     "subscription": {
        #         "subScribeToEmails": True
        #     },
        #     "userDetails": {
        #         "biAccount": {
        #             "birthDay": self.birthDay,
        #             "birthMonth": self.birthMonth,
        #             "birthYear": self.birthYear
        #         },
        #         "confirmPassword": self.password,
        #         "email": self.email,
        #         "firstName": self.firstName,
        #         "isAcceptCommunity": True,
        #         "lastName": self.lastName,
        #         "login": self.email,
        #         "password": self.password
        #     }
        # }
        # print(json.dumps(data))

    def SignUp(self, firstName, lastName, birthDay, birthMonth, birthYear, email, password, ):
        msg = ""
        # 调用 GenerateInfos 方法生成信息
        self.generate_infos(firstName, lastName, birthDay, birthMonth, birthYear, email, password)

        url = "https://api.sephora.com/v1/users/profile"
        data = {
            "isJoinBi": True,
            "userDetails": {
                "lastName": self.lastName,
                "firstName": self.firstName,
                "securityQuestion": "",
                "login": self.email,
                "confirmPassword": self.password,
                "profileId": "",
                "isAcceptCommunity": True,
                "securityAnswer": "",
                "password": self.password,
                "nickName": "",
                "email": self.email,
                "phoneNumber": ""
            },
            "subscription": {
                "zipCode": "",
                "subScribeToEmails": True,
                "subScribeToSms": False
            },
            "isKeepSignedIn": True
        }

        # data = {
        #     "isJoinBi": True,
        #     "isKeepSignedIn": True,
        #     "subscription": {
        #         "subScribeToEmails": True
        #     },
        #     "userDetails": {
        #         "biAccount": {
        #             "birthDay": self.birthDay,
        #             "birthMonth": self.birthMonth,
        #             "birthYear": self.birthYear
        #         },
        #         "confirmPassword": self.password,
        #         "email": self.email,
        #         "firstName": self.firstName,
        #         "isAcceptCommunity": True,
        #         "lastName": self.lastName,
        #         "login": self.email,
        #         "password": self.password
        #     }
        # }
        print(json.dumps(data))

        # 调用 SephoraPost 方法发送 POST 请求
        str1 = self.SephoraPost(url, json.dumps(data), True)
        print(str1)

        if not str1:
            return False, msg

        # 使用正则表达式提取错误消息
        error_messages_match = re.search(r'"errorMessages":\["(.*?)"\\]', str1)
        if error_messages_match:
            msg = error_messages_match.group(1)
            return False, msg

        elif "Access Denied" in str1:
            msg = f"Access Denied: You don't have permission to access '{url}' on this server"
            return False, msg

        try:
            jobj = json.loads(str1)
            if "accessToken" in jobj and "refreshToken" in jobj:
                self.accessToken = jobj["accessToken"]
                self.refreshToken = jobj["refreshToken"]
                self.ssiToken = jobj.get("ssiToken", "")
                self.profileId = jobj.get("profileId", "")
                print(
                    f"accessToken:{self.accessToken}\nrefreshToken:{self.refreshToken}\nprofileId:{self.profileId}\nssiToken:{self.ssiToken}")
                # SaveInfos()
                return True, None

        except Exception:
            pass

        msg = str1
        return False, msg

    def CheckResponse(self, str1):
        msg = ""

        if not str1:
            msg = "网络异常"
            return False, msg

        j = json.loads(str1)

        if "errorCode" in str1:
            msg = j.get("errorMessages", "")

            if "SAAT Header" in msg:
                if not self.AuthenticateDevice():
                    return False, msg
                if not self.Login(self.email, self.password):
                    return False, msg
                if self.AccessToken():
                    msg = "next"
                    return False, msg
            if "Request cannot be completed as checkout is not initiated" in msg:
                if self.OrderInit():
                    msg = "next"
                    return True, msg
                else:
                    return False, msg

            return False, msg

        if '{"profileLocale":"US","profileStatus":' in str1 or '{"addressList":[],"profileLocale":"US","profileStatus":4}' in str1:
            if not self.AuthenticateDevice():
                return False, msg
            if not not self.Login(self.email, self.password):
                return False, msg
            if self.AccessToken():
                msg = "next"
                return False, msg

            return False, msg

        if "Access Denied" in str1:
            msg = "You don't have permission to access on this server"
            return False, msg

        if "out of stock" in str1:
            msg = "Sorry, this item is out of stock."
            return False, msg

        msg = ""
        return True, msg

    def OrderInit(self):
        msg = ""
        url = "https://api.sephora.com/v1/checkout/order/init"
        data = {
            "isApplePayFlow": False,
            "RopisCheckout": False,
            "orderId": "current",
            "profileId": self.profileId,
            "isPaypalFlow": False
        }
        data = json.dumps(data)
        str1 = self.SephoraPost(url, data)

        for i in range(2):
            if self.CheckResponse(str1):
                msg = ""
                return True
            elif msg == "next":
                continue

        return True

    def Login(self, email, password):
        self.httpClient.headers["CLIENT_AUTH_SAAT"] = "6a3eacc0621fee90e5bfcac2599f02061daac7f4f8712e5bd68d81ef65268607"
        random_string = str(uuid.uuid4()).upper()
        msg = ""
        uuid_str = str(uuid.uuid4())
        url = "https://api.sephora.com/api/auth/v1/login"
        password_hash = self.Sha256String(uuid_str)
        data = {
            "email": email,
            "loginForCheckout": True,
            "password": password,
            "randomNumber": password_hash
        }
        print("1111111111111" + json.dumps(data))

        # 调用 SephoraPost 方法发送登录请求
        str1 = self.SephoraPost(url, json.dumps(data), True)
        print(str1)

        if not str1:
            msg = "网络异常"
            return False, msg

        # 使用正则表达式提取错误消息
        error_message_match = re.search(r'"errorMessage":"(.*?)"', str1)
        if error_message_match:
            msg = error_message_match.group(1)
            return False, msg

        if "Access Denied" in str1:
            msg = f"You don't have permission to access '{url}' on this server"
            return False, msg

        try:
            jobj = json.loads(str1)
            token = jobj.get("token", "")

            if token:
                url = "https://api.sephora.com/api/auth/v1/generateToken"
                data = {
                    "email": email,
                    "keepSignedIn": True,
                    "loginForCheckout": True,
                    "password": password,
                    # "randomNumber": uuid_str,
                    "randomNumber": random_string,
                    "token": token
                }
                print("2222222222222" + json.dumps(data))

                # 调用 SephoraPost 方法生成令牌
                str2 = self.SephoraPost(url, json.dumps(data), True)

                if not str2:
                    msg = "网络异常"
                    return False, msg

                # 使用正则表达式提取错误消息
                error_message_match = re.search(r'"errorMessage":"(.*?)"', str2)
                if error_message_match:
                    msg = "GenerateToken" + error_message_match.group(1)
                    return False, msg

                if "Access Denied" in str2:
                    msg = f"You don't have permission to access '{url}' on this server"
                    return False, msg

                jobj = json.loads(str2)

                if "tokens" in jobj:
                    self.accessToken = jobj["tokens"]["accessToken"]
                    self.refreshToken = jobj["tokens"]["refreshToken"]
                    self.ssiToken = jobj["ssiToken"]
                    # self.email = email
                    # self.password = password
                    self.profileId = jobj["profileId"]
                    print(
                        f"accessToken:{self.accessToken}\nrefreshToken:{self.refreshToken}\nssiToken:{self.ssiToken}\nprofileId:{self.profileId}")
                    # SaveInfos()
                    return True, None
        except Exception:
            pass

        msg = str1
        return False, msg

    # 查看购物车
    def GetBasket(self):
        jArray = []
        msg = ""

        url = "https://api.sephora.com/v1/shopping-cart/basket"

        for i in range(2):
            str1 = self.SephoraGet(url)
            # {"SDUProduct":{"defaultSkuId":"2610293","isSDUAddedToBasket":false,"productId":"P483900","skuTrialEligibility":true,"skuTrialPeriod":"30"},"appliedCBRValue":0.0,"appliedPromotions":[],"availableBiPoints":0,"availablePayments":["PAYPAL"],"basketLevelMessages":[{"key":"basket.amountToFreeShipping","messageContext":"basket.amountToFreeShipping","messageLogo":"freeShipLogo","messages":["You're only $50.00 away from Free Shipping."],"type":"message"}],"basketSwitchAvailable":true,"creditCardImage":"/contentimages/creditcard/cardicon/2019-04-01-sephora-cc-icon-d-us-ca-slice.jpg","currency":"USD","digitalGiftMessagingStatus":1,"discountAmount":"$0.00","firstBuyDiscountTotal":"$0.00","firstBuyIncentive":"25%","firstBuyOrderDiscount":"25%","firstIncentiveDiscountUpdated":false,"isAfterpayCheckoutEnabled":false,"isAfterpayEnabledForProfile":true,"isApplePayEnabled":true,"isBIPointsAvailable":true,"isEligibleToReplacePaidFlash":false,"isGuestCheckoutEnabled":false,"isKlarnaCheckoutEnabled":false,"isMaxCCRewardsLimitReached":false,"isPaypalPaymentEnabled":true,"itemCount":0,"items":[],"itemsByBasket":[],"maxEligibleCBR":0.0,"maxSamplesAllowedPerOrder":2,"messages":["You're only $50.00 away from Free Shipping."],"netBeautyBankPointsAvailable":0,"orderId":"current","orderSalesChannel":"default","pickupBasket":{"availableBiPoints":0,"availablePayments":["PAYPAL"],"basketLevelMessages":[{"messageContext":"basket.storePickupOnHold","messages":["Your selected store is no longer offering Buy Online & Pickup In-Store. Please choose a different store."],"type":"warning"},{"messageContext":"basket.pickupItems.genericErrorMessage","messages":["There’s an error in this basket. Please view items for details"],"type":"warning"}],"basketSwitchAvailable":true,"currency":"USD","digitalGiftMessagingStatus":0,"estimatedTax":"$0.00","estimatedTotal":"$0.00","isAfterpayCheckoutEnabled":false,"isAfterpayEnabledForProfile":true,"isApplePayEnabled":false,"isGuestCheckoutEnabled":false,"isKlarnaCheckoutEnabled":false,"isMaxCCRewardsLimitReached":false,"isPaypalPaymentEnabled":false,"itemCount":0,"items":[],"netBeautyBankPointsAvailable":0,"orderId":"66584858588","orderSalesChannel":"default","potentialBeautyBankPoints":0,"profileId":"52652783364","profileLocale":"US","profileStatus":2,"rawSubTotal":"$0.00","realTimeVIBMessages":[],"redeemedBiPoints":0,"showPaypalPopUp":true,"subtotal":"$0.00","warnings":["Your selected store is no longer offering Buy Online & Pickup In-Store. Please choose a different store.","There’s an error in this basket. Please view items for details"]},"pickupbasketItemCount":0,"potentialBeautyBankPoints":0,"profileId":"52652783364","profileLocale":"US","profileStatus":2,"rawSubTotal":"$0.00","realTimeVIBMessages":[],"redeemedBiPoints":0,"remainToFreeShipping":"$50.00","showPaypalPopUp":true,"subtotal":"$0.00"}
            # print(str1)
            if self.CheckResponse(str1):
                jobj = json.loads(str1)
                if "items" in jobj:
                    jArray = jobj["items"]
                    print(f"购物车：{jArray}")
                return True, jArray, msg
            elif msg == "next":
                continue

        return True, jArray, msg

    # 获取促销码
    def GetCouponCode(self):
        msg = ""
        url = "https://api.sephora.com/v1/catalog/screens/beautyoffers?countryCode=US&regions=region1,region2,region3"

        for i in range(2):
            str1 = self.SephoraGet(url)
            # print(str1)
            if "breadcrumbs" in str1:
                msg = str1
                return True, msg
            elif self.CheckResponse(str1):
                msg = ""
                return True, msg
            elif msg == "next":
                continue
            else:
                return False

        return False

    # 获取地址
    def GetAddress(self):
        msg = ""
        jArray = None
        url = f"https://api.sephora.com/v1/checkout/profiles/{self.profileId}/addresses?country=US"

        for i in range(2):
            str1 = self.SephoraGet(url)
            # print(str1)
            if "{\"addressList\":[],\"profileLocale\":\"US\",\"profileStatus\":" in str1:
                # {"addressList": [], "profileLocale": "US", "profileStatus": 4}
                print(f"地址：{jArray}")
                return True
            elif self.CheckResponse(str1):
                jobj = json.loads(str1)
                if "addressList" in jobj:
                    jArray = jobj["addressList"]
                    print(f"地址：{jArray}")
                msg = ""
                return True, jArray
            elif msg == "next":
                continue
            else:
                return False

        return False

    # 获取订单
    def GetOrders(self):
        msg = ""
        jArray = None
        url = f"https://api.sephora.com/v1/users/profiles/{self.profileId}/orders?itemsPerPage=60&currentPage=0"

        for i in range(2):
            str1 = self.SephoraGet(url)

            if "{\"orderCount\":0,\"orders\":[],\"profileLocale\":\"US\",\"profileStatus\":" in str1:
                print(f"订单：{jArray}")
                return True
            elif self.CheckResponse(str1):
                jobj = json.loads(str1)
                msg = ""
                jArray = jobj["orders"]
                print(f"订单：{jArray}")
                return True
            elif msg == "next":
                continue
            else:
                return False

        return False

    # 添加地址
    def AddAddress(self, ac):
        # url = "https://api.sephora.com/v1/checkout/orders/shippingGroups/shippingAddress"
        url = "https://api.sephora.com/v1/users/profiles/address"
        jobj = {
            "addressValidated": True,
            "isDefaultAddress": True,
            "isPOBoxAddress": False,
            "saveToProfile": True,
            "byPassProfileCount": True,
            "addressType": "Unknown"
        }
        tempObj = {
            "address1": ac.address1,
            "address2": ac.address2,
            "country": "US",
            "firstName": ac.firstName,
            "lastName": ac.lastName,
            "phone": ac.phone,
            "postalCode": ac.postalCode,
            "state": ac.state,
            "city": ac.city
        }

        jobj["address"] = tempObj
        data = json.dumps(jobj)
        str1 = self.SephoraPost(url, data)
        print(str1)
        if str1 is None:
            msg = "网络异常"
            return False, msg
        elif "errorMessages" in str1:
            j = json.loads(str1)
            msg = j["errorMessages"]
            return False, msg
        elif "Access Denied" in str1:
            msg = "You don't have permission to access \"" + url + "\" on this server"
            return False, msg
        msg = ""
        return True, msg

    # 添加购物车
    def AddItems(self, skuList):
        # skuList = [
        #     {
        #         "skuId": "2495497",
        #         "qty": 1,
        #         "productId": "P455936",
        #     },
        #     {
        #         "skuId": "123456",
        #         "qty": 2,
        #         "productId": "P789012",
        #     }
        # ]
        request_body = {
            "orderId": "current",
            "skuList": [],
            "profileId": self.profileId
        }
        for skuItem in skuList:
            sku_entry = {
                "isAcceptTerms": False,
                "replenishmentSelected": False,
                "skuId": skuItem["skuId"],
                "qty": skuItem["qty"],
                "productId": skuItem["productId"]
            }
            request_body["skuList"].append(sku_entry)

        url = "https://api.sephora.com/v1/shopping-cart/basket/items"

        str1 = self.SephoraPost(url, json.dumps(request_body), True)
        # print(str1)

        if str1 is None:
            msg = "网络异常"
            return False, msg
        elif "errorCode" in str1:
            j = json.loads(str1)
            msg = j.get("errorMessages", "")
            if "out of stock" in str1:
                msg = "Sorry, this item is out of stock."
                return False, msg
            return False, msg
        elif "Access Denied" in str1:
            msg = "You don't have permission to access \"" + url + "\" on this server"
            return False, msg

        msg = str1
        return True, msg

    # 获取样品
    def GetSamples(self):
        msg = ""
        scs = []
        number = 0
        url = "https://api.sephora.com/v1/util/samples"
        str1 = ""

        for i in range(2):
            str1 = self.SephoraGet(url)
            print(str1)
            if "allowedQtyPerOrder" in str1:
                obj = json.loads(str1)
                number = int(obj["allowedQtyPerOrder"])
                for j in obj["samples"]:
                    scs.append(SampleClass(j["skuId"], j["gridImage"]))
                return True, number, scs
            elif self.CheckResponse(str1):
                jobj = json.loads(str1)
                return True, number, scs
            elif msg == "next":
                continue
            else:
                return False, number, scs

        return False, number, scs

    # 添加样品
    def AddSamples(self, ids):
        url = "https://api.sephora.com/v1/shopping-cart/basket/samples"

        # 构建请求体
        data = {"sampleSkuIdList": ids}
        data = json.dumps(data)

        # 发送POST请求
        str1 = self.SephoraPost(url, data, True)
        print(str1)

        if str1 is None:
            msg = "网络异常"
            return False, msg
        elif "errorCode" in str1:
            j = json.loads(str1)
            msg = j.get("errorMessages", "")
            if "out of stock" in str1:
                msg = "Sorry, this item is out of stock."
                return False, msg
            return False, msg
        elif "Access Denied" in str1:
            msg = "You don't have permission to access \"" + url + "\" on this server"
            return False, msg

        msg = str1
        return True, msg

    # 移除地址
    def RemoveAddress(self, addressIds):
        msg = ""
        success = []

        for addressId in addressIds:
            url = "https://api.sephora.com/v1/checkout/orders/current/shippingGroups/0/shippingAddress/" + addressId
            str1 = self.SephoraDelete(url)

            if str1 is None:
                msg += addressId + " : 网络异常" + "\r\n"
                return False, msg
            elif "errorCode" in str1:
                error_message = str1.split('"errorMessage":"', 1)[1].split('"', 1)[0]
                msg += addressId + " : " + error_message + "\r\n"
                return False, msg
            elif "Access Denied" in str1:
                msg += addressId + " : Access Denied: You don't have permission to access \"" + url + "\" on this server"
                return False, msg
            success.append(addressId)

        if len(success) == len(addressIds):
            return True
        else:
            return False

    # 移除购物车
    def RemoveItems(self, pro_info):
        # 调用示例
        # pro_info = [("2181006", "P441101"), ("123456", "P789012")]  # 替换为实际的 SKU ID 和 Product ID 组合
        msg = ""
        success = []

        for sku_id, product_id in pro_info:
            url = f"https://api.sephora.com/v1/shopping-cart/baskets/current/items/{sku_id}?modifyConfirmed=true&productId={product_id}&"
            str1 = self.SephoraDelete(url)

            if str1 is None:
                msg += f"{sku_id} : 网络异常\n"
                return False, msg
            elif "errorCode" in str1:
                error_message = str1.split('"errorMessage":"', 1)[1].split('"', 1)[0]
                msg += f"{sku_id} : {error_message}\n"
                return False, msg
            elif "Access Denied" in str1:
                msg += f"{sku_id} : Access Denied: You don't have permission to access \"{url}\" on this server\n"
                return False, msg
            success.append(sku_id)

        if len(success) == len(pro_info):
            return True
        else:
            return False

    # 添加礼品卡
    def AddGiftCard(self, number, pin):
        url = "https://api.sephora.com/v1/checkout/orders/paymentGroups/giftCard"
        data = {
            "gcNumber": number,
            "gcPin": pin
        }
        data = json.dumps(data)
        msg = ""
        for i in range(2):
            str1 = self.SephoraPost(url, data, True)
            if self.CheckResponse(str1):
                str1 = json.loads(str1)
                if "orderPriceInfo" in str1:
                    msg = str1
                    return True, msg
                elif "Access Denied" in str1:
                    msg = f"You don't have permission to access \"{url}\" on this server"
                    return False, msg
                elif msg == "next":
                    continue
                else:
                    return False

    # 移除礼品卡
    def RemoveGiftCards(self):
        jArray = None
        url = "https://api.sephora.com/v1/checkout/orders/current?skipApis=header%2CshippingGroups"
        str1 = ""
        for i in range(2):
            msg = ""
            str1 = self.SephoraGet(url)
            if self.CheckResponse(str1):
                jobj = json.loads(str1)
                if "paymentGroups" in jobj:
                    jArray = jobj["paymentGroups"]["paymentGroupsEntries"]
                    for j in jArray:
                        paymentGroupType = j["paymentGroupType"]
                        if paymentGroupType == "GiftCardPaymentGroup":
                            paymentGroupId = j["paymentGroup"]["paymentGroupId"]
                            self.SephoraDelete(
                                f"https://api.sephora.com/v1/checkout/orders/current/paymentGroups/{paymentGroupId}/giftCard")
                return True
            elif msg == "next":
                continue

        return True

    # 提交订单
    def SubmitOrder(self):
        msg = ""
        url = "https://api.sephora.com/v1/checkout/submitOrder"
        data = {
            "orderId": "current",
            "originOfOrder": "androidNativeApp",
            "profileId": self.profileId
        }
        data = json.dumps(data)
        str1 = self.SephoraPost(url, data)

        for i in range(2):
            if "orderId" in str1:
                msg = str1.split('"orderId":"', 1)[1].split('"', 1)[0]
                return True, msg
            elif self.CheckResponse(str):
                msg = ""
                return True, msg
            elif msg == "next":
                continue
            else:
                return False

        return True


if __name__ == '__main__':
    s = SephoraClass()
    s.registerDevice()
    s.AuthenticateDevice()
    s.AccessToken()
    s.SignUp(s.firstName, s.lastName, s.birthDay, s.birthMonth, s.birthYear, s.email, s.password)
    # s.GetBasket()
    # s.Login(s.email, s.password)
    # s.GetCouponCode()
    # s.GetAddress()
    # s.GetOrders()
    # s.OrderInit()
    ac = AddressClass()
    ac.firstName = "Wyn"
    ac.lastName = "Verdu"
    ac.phone = "0701112358"
    ac.address1 = "1 Sandingham Way"
    ac.address2 = ""
    ac.postalCode = "77384-4492"
    ac.city = "Conroe"
    ac.state = "TX"
    s.AddAddress(ac)
    s.GetAddress()
    skuList = [
        {
            "skuId": "2495497",
            "qty": 1,
            "productId": "P455936",
        },
        {
            "skuId": "2181006",
            "qty": 2,
            "productId": "P441101",
        }
    ]
    s.AddItems(skuList)
    s.GetBasket()
    s.GetSamples()
    sample_ids = ["2353761", "2467587"]
    s.AddSamples(sample_ids)
    s.GetBasket()
    pro_info = [("2495497", "P455936"), ("2181006", "P441101")]
    s.RemoveItems(pro_info)
    s.GetBasket()
    print(s.AddGiftCard("6203496513632674", "47255481"))
